package app.jobs.asyn;

import app.Const;
import app.constant.MemberConstant;
import app.constant.OrderConstant;
import app.kit.TypeKit;
import app.models.member.Account;
import app.models.member.AccountAmount;
import app.models.member.MemberProduct;
import app.models.member.RedeemProduct;
import app.models.order.Order;
import app.models.order.TradeMoney;
import app.models.product.Product;
import app.services.AccountService;
import app.services.OrderService;
import bank.BankConstant;
import bank.BankService;
import bank.resp.MerchantAccntRspDto;
import bank.resp.TransferMerchantRspDto;
import com.google.common.base.Optional;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import goja.Logger;
import goja.StringPool;
import goja.job.Job;
import org.joda.time.DateTime;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.List;

import static app.Const.FIELD_AMOUNT;
import static app.Const.FIELD_MEMBER;
import static app.Const.FIELD_NAME;
import static app.Const.FIELD_ORDER_ID;
import static app.Const.FIELD_PRODUCT;
import static app.Const.FIELD_STATUS;
import static app.models.member.MemberProduct.FIELD_PLAYMONEY_STATUS;
import static app.models.member.MemberProduct.FIELD_REDEEM_STATUS;

/**
 * <p> 即时打款JOB</p>
 *
 * @author sogYF
 * @version 1.0
 * @since JDK 1.6
 */
public class InstantPayJob extends Job {

    private final List<TradeMoney> tradeMoneyList;

    private final int type;

    public InstantPayJob(List<TradeMoney> tradeMoneyList, int type) {
        this.tradeMoneyList = tradeMoneyList;
        this.type = type;
    }


    @Override
    public void doJob() throws Exception {
        super.doJob();
        switch (type) {
            case TradeMoney.TRANSFER_TYPE:
                invokeTransfer();
                break;
            case TradeMoney.CANCEL_TYPE: {
                invokeCancel();
                break;
            }
            case TradeMoney.RAISED_SUCCESS_TYPE:
                invokeRaisedSuccess();
                break;
            case TradeMoney.PAY_FAIL_TYPE:
                invokePayFailTrade();
                break;

        }


    }

    private void invokePayFailTrade() {

        Logger.info("Started Pay Fail Trade back amount...");

        DateTime now = DateTime.now();
        for (final TradeMoney tradeMoney : tradeMoneyList) {
            // 会员编号
            String memebr_code = tradeMoney.getStr("membercode");
            // 打款金额
            final BigDecimal amount = tradeMoney.adjustAmount();
            final int memberId = TypeKit.getInt(tradeMoney, FIELD_MEMBER);

            String productName = tradeMoney.getStr(FIELD_NAME);

            final Order order = OrderService.me.buildOrder(memberId, 0, "融理平台", BankConstant.MERCHANT_PRODUCT_NO, StringPool.EMPTY, OrderConstant.ORDRFAIL);
            // 订单纪录金额
            order.set("trade_amount", amount);
            String orderNo = order.getStr("trade_no");
            String desc = "会员" + memebr_code + "交易失败" + productName + "退款操作";
            Optional<TransferMerchantRspDto> cancelMerchant =
                    BankService.me.transferMerchantAccnt(now, now, memebr_code, orderNo,
                            amount, desc);
            if (cancelMerchant.isPresent() && cancelMerchant.get().isSuccess()) {
                // 打款成功，更改数据状态
                tradeMoney.set(FIELD_STATUS, TradeMoney.SUCCESS_STATUS);
                tradeMoney.set("money_time", now.toDate());

                order.set(FIELD_STATUS, OrderConstant.TRADE_SUCCESS);
                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return order.save()
                                && tradeMoney.update();
                    }
                });
            } else {
                Logger.error("Ended back singles has error!");
                tradeMoney.set(FIELD_STATUS, TradeMoney.FAIL_STATUS);
                order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);

                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return order.save() && tradeMoney.update() ;
                    }
                });
            }
        }
        Logger.info("Ended Pay Fail Trade back amount...");
    }

    private void invokeRaisedSuccess() {

        Logger.info("Started Raised Success account Withdrawals...");
        DateTime now = DateTime.now();
        for (final TradeMoney tradeMoney : tradeMoneyList) {
            // 提现总募集成功金额
            final BigDecimal amount = tradeMoney.getBigDecimal("raised_mount").setScale(2, BigDecimal.ROUND_HALF_UP);

            String productName = tradeMoney.getStr(FIELD_NAME);
            String desc = "产品[" + productName + "]募集成功结算提现";

            final Order order = OrderService.me.buildOrder(0, 0, "融理平台",BankConstant.MERCHANT_PRODUCT_NO, StringPool.EMPTY,
                    OrderConstant.WITHDRAWALS);
            order.set("trade_amount", amount);
            order.set("remark", desc);
            String orderNo = order.getStr("trade_no");

            Optional<MerchantAccntRspDto> chargingAccnt = BankService.me.withdrawMerchantAccnt(DateTime.now(), orderNo, amount);
            if (chargingAccnt.isPresent()) {
                boolean ok = chargingAccnt.get().getOrderStatus() == OrderConstant.TRADE_SUCCESS;
                if (ok) {
                    // 打款成功，更改数据状态
                    tradeMoney.set(FIELD_STATUS, TradeMoney.SUCCESS_STATUS);
                    tradeMoney.set("money_time", now.toDate());
                    order.set(FIELD_STATUS, OrderConstant.TRADE_SUCCESS);

                } else {
                    tradeMoney.set(FIELD_STATUS, TradeMoney.FAIL_STATUS);
                    order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
                }
            } else {

                tradeMoney.set(FIELD_STATUS, TradeMoney.FAIL_STATUS);
                order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
            }

            Db.tx(new IAtom() {
                @Override
                public boolean run() throws SQLException {
                    return order.save() && tradeMoney.update();

                }
            });
        }
        Logger.info("Ended Raised Success account Withdrawals...");
    }

    /**
     * 退单即时打款
     */
    private void invokeCancel() {
        Logger.info("Started back singles section....");

        DateTime now = DateTime.now();
        for (final TradeMoney tradeMoney : tradeMoneyList) {
            // 会员编号
            String memebr_code = tradeMoney.getStr("membercode");
            // 原始金额
            BigDecimal amount = tradeMoney.getBigDecimal(FIELD_AMOUNT);
            // 打款金额
            final BigDecimal adjustAmount = tradeMoney.adjustAmount();
            final int memberId = TypeKit.getInt(tradeMoney, FIELD_MEMBER);
            // 会员产品
            final int member_product = tradeMoney.getNumber("member_product").intValue();


            String productName = tradeMoney.getStr(FIELD_NAME);
            int productId = TypeKit.getInt(tradeMoney, FIELD_PRODUCT);

            String productCode = tradeMoney.getStr("productcode");
            final Order order = OrderService.me.buildOrder(memberId, productId, productName, productCode, StringPool.EMPTY, OrderConstant.RPN_TYPE);
            // 订单纪录金额
            order.set("trade_amount", adjustAmount);
            String orderNo = order.getStr("trade_no");
            String desc = "会员" + memebr_code + "退单产品" + productName + "打款操作";
            Optional<TransferMerchantRspDto> cancelMerchant =
                    BankService.me.transferMerchantAccnt(now, now, memebr_code, orderNo, adjustAmount, desc);
            final MemberProduct memberProduct = new MemberProduct();
            memberProduct.set(StringPool.PK_COLUMN, member_product);
            if (cancelMerchant.isPresent() && cancelMerchant.get().isSuccess()) {
                // 打款成功，更改数据状态
                tradeMoney.set(FIELD_STATUS, TradeMoney.SUCCESS_STATUS);
                tradeMoney.set("money_time", now.toDate());

                order.set(FIELD_STATUS, OrderConstant.TRADE_SUCCESS);
                // 退单产品
                final RedeemProduct redeemProduct = RedeemProduct.dao.findByMemberProduct(member_product, memberId);
                redeemProduct.set(Const.FIELD_STATUS, MemberConstant.REDEM_SUCCESS);

                final AccountAmount accountAmount = AccountAmount.dao.earning(memberId, "产品[" + productName + "]退单", now, adjustAmount);

                memberProduct.set(FIELD_PLAYMONEY_STATUS, MemberConstant.PLAYMONEY_OK);
                // 退单后 回写产品可售金额
                final Product product = Product.dao.findById(productId);
                product.cancelBuy(amount);

                final Account account = AccountService.me.expendAccount(adjustAmount, memberId);
                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return order.save()
                                && tradeMoney.update()
                                && redeemProduct.update()
                                && accountAmount.save()
                                && account.update()
                                && memberProduct.update()
                                && product.update();
                    }
                });
            } else {
                Logger.error("Ended back singles has error!");
                tradeMoney.set(FIELD_STATUS, TradeMoney.FAIL_STATUS);
                order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
                memberProduct.set(FIELD_REDEEM_STATUS, MemberConstant.REDEEM_FAIL);
                memberProduct.set(FIELD_PLAYMONEY_STATUS, MemberConstant.PLAYMONEY_NO);

                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return order.save() && tradeMoney.update() && memberProduct.update();
                    }
                });
            }
        }
        Logger.info("Ended back singles section....");
    }

    private void invokeTransfer() {

        Logger.info("Started to fight money transfers....");

        DateTime now = DateTime.now();
        for (final TradeMoney tradeMoney : tradeMoneyList) {
            // 会员编号
            String memebr_code = tradeMoney.getStr("membercode");
            // 会员产品
            final int member_product = tradeMoney.getNumber("member_product").intValue();
            // 打款金额
            final BigDecimal amount = tradeMoney.adjustAmount();
            final int memberId = TypeKit.getInt(tradeMoney, FIELD_MEMBER),
                    orderId = TypeKit.getInt(tradeMoney, FIELD_ORDER_ID);
            String productName = tradeMoney.getStr(FIELD_NAME);
            int productId = TypeKit.getInt(tradeMoney, FIELD_PRODUCT);

            Order ex_order = Order.dao.findById(orderId);
            final boolean ex_fail = TypeKit.getStatus(ex_order) == OrderConstant.TRADE_FAILURE;
            if (ex_fail) {
                String productCode = tradeMoney.getStr("productcode");
                ex_order = OrderService.me.buildOrder(memberId, productId, productName, productCode, StringPool.EMPTY, OrderConstant.TFR_PAY_TYPE);
            }
            final Order order = ex_order;
            String orderNo = order.getStr("trade_no");
            String desc = "会员" + memebr_code + "转让产品" + productName + "打款操作";
            Optional<TransferMerchantRspDto> cancelMerchant =
                    BankService.me.transferMerchantAccnt(now, now, memebr_code, orderNo,
                            amount, desc);
            final MemberProduct memberProduct = new MemberProduct();
            memberProduct.set(StringPool.PK_COLUMN, member_product);
            if (cancelMerchant.isPresent() && cancelMerchant.get().isSuccess()) {
                // 打款成功，更改数据状态
                tradeMoney.set(FIELD_STATUS, TradeMoney.SUCCESS_STATUS);
                tradeMoney.set("money_time", now.toDate());

                order.set(FIELD_STATUS, OrderConstant.TRADE_SUCCESS);

                memberProduct.set(FIELD_PLAYMONEY_STATUS, MemberConstant.PLAYMONEY_OK);

                final Account account = AccountService.me.expendAccount(amount, memberId);
                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        boolean order_ok = ex_fail ? order.save() : order.update();
                        return order_ok
                                && tradeMoney.update()
                                && account.update()
                                && memberProduct.update();

                    }
                });
            } else {
                Logger.error("Ended transfer money has error!");
                tradeMoney.set(FIELD_STATUS, TradeMoney.FAIL_STATUS);
                order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
                memberProduct.set(FIELD_REDEEM_STATUS, MemberConstant.REDEEM_FAIL);
                memberProduct.set(FIELD_PLAYMONEY_STATUS, MemberConstant.PLAYMONEY_NO);

                Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        boolean order_ok = ex_fail ? order.save() : order.update();
                        return order_ok && tradeMoney.update() && memberProduct.update();
                    }
                });
            }
        }
        Logger.info("Ended to fight money transfers....");
    }
}
